package com.ebupt.migu.music.label.service.impl;

import com.ebupt.migu.common.pojo.CustomerFileBean;
import com.ebupt.migu.common.pojo.CustomerMergeRequestBean;
import com.ebupt.migu.common.pojo.MusicRuleRequestBean;
import com.ebupt.migu.globalpopup.entity.ConditionRelation;
import com.ebupt.migu.music.approve.mapper.ApproveMapper;
import com.ebupt.migu.music.common.constants.ApproveConstans;
import com.ebupt.migu.music.common.constants.StrategyConstants;
import com.ebupt.migu.music.common.entity.ResultObject;
import com.ebupt.migu.music.common.exception.MyException;
import com.ebupt.migu.music.common.exception.StatusEnum;
import com.ebupt.migu.music.label.entity.LabelCustomerDetailRequestBean;
import com.ebupt.migu.music.label.entity.LabelCustomerRequestBean;
import com.ebupt.migu.music.label.entity.LabelCustomerResponseBean;
import com.ebupt.migu.music.label.entity.LabelCustomerResponseCodeEnum;
import com.ebupt.migu.music.label.mapper.LabelCustomerMapper;
import com.ebupt.migu.music.label.service.LabelCustomerService;
import com.ebupt.migu.music.label.utils.SftpUtils;
import com.ebupt.migu.music.redis.service.RedisService;
import com.ebupt.migu.music.strategy.mapper.StrategyMapper;
import com.ebupt.migu.restapi.DownloadByFtp;
import com.ebupt.migu.restapi.RestHttpPost;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

/**
 * @description: TODO
 * @author: liuyangyang@ebupt.com
 * @date: 2021/8/13 15:21
 */
@Slf4j
@Service
public class LabelCustomerServiceImpl implements LabelCustomerService {
    @Autowired
    private LabelCustomerMapper mapper;
    @Resource
    private RedisService redisService;
    @Resource
    private StrategyMapper strategyMapper;
    @Resource
    private ApproveMapper approveMapper;
    @Autowired
    SftpUtils sftpUtils;
    @Value("${label.prefix}")
    private String LABEL_PREFIX;
    @Value("${label.customer_rule}")
    private String CUSTOMER_RULE;
    @Value("${label.customer_merge}")
    private String CUSTOMER_MERGE;
    @Value("${label.prefix}")
    private String labelPrefix;
    @Value("${label.post_url}")
    private String postUrl;

    /**
     * 判定当前客群是否需要将结果集导入redis
     *
     * @param groupId
     * @return
     */
    @Override
    public ResultObject dynamicOnly(String groupId) {
        ResultObject res = new ResultObject();
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        Map<String, String> map = new HashMap<>();
        map.put("groupId", groupId);
        res.setData(mapper.dynamicOnly(map));
        return res;
    }

    /**
     * 查询is_dynamic_customer 和 is_static_customer的值
     *
     * @param groupId
     * @return
     */
    @Override
    public ResultObject dynamicAndStaticStatus(String groupId) {
        ResultObject res = new ResultObject();
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        Map<String, String> map = new HashMap<>();
        map.put("groupId", groupId);
        res.setData(mapper.dynamicAndStaticStatus(map));
        return res;
    }

    /**
     * 更新客群状态
     *
     * @param bean
     * @param param dynamic - 动态标签 static - 统一标签
     * @return
     */
    @Override
    public LabelCustomerResponseBean updateLabelCustomerStatus(LabelCustomerRequestBean bean, String param) {
        LabelCustomerResponseBean responseBean = new LabelCustomerResponseBean();
        try {
            // 客群ID不能为空
            if (null == bean.getCustomerId() || "".equals(bean.getCustomerId())) {
                responseBean.setCode(LabelCustomerResponseCodeEnum.CUSTOMER_NOT_EXIST.getCode());
                responseBean.setMsg(LabelCustomerResponseCodeEnum.CUSTOMER_NOT_EXIST.getMsg());
                return responseBean;
            }
            HashMap<String, String> userGroupInfo = new HashMap<>();
            userGroupInfo.put("groupId", bean.getCustomerId());
            // 失败入库
            if ("2".equals(bean.getCustomerStatus())) {
                userGroupInfo.put("createStatus", "6");
                userGroupInfo.put("remark", bean.getRemark());
                // 更新数据库
                mapper.updateUserGroupInfo(userGroupInfo);
                // 更新使用该人群的待进行策略
                updateStrategyInfo(bean.getCustomerId());
                responseBean.setCode(LabelCustomerResponseCodeEnum.SUCCESS.getCode());
                responseBean.setMsg(LabelCustomerResponseCodeEnum.SUCCESS.getMsg());
                return responseBean;
            }
            // 分箱人群进入待更新状态
            if ("3".equals(bean.getCustomerStatus())) {
                userGroupInfo.put("createStatus", "3");
                userGroupInfo.put("clientUser", bean.getUidNum());
                userGroupInfo.put("mobileUser", bean.getMsisdnNum());
                userGroupInfo.put("deviceUser", bean.getDeviceNum());
                // 更新数据库
                mapper.updateUserGroupInfo(userGroupInfo);
                responseBean.setCode(LabelCustomerResponseCodeEnum.SUCCESS.getCode());
                responseBean.setMsg(LabelCustomerResponseCodeEnum.SUCCESS.getMsg());
                return responseBean;
            }
            // 来自动态标签的入库请求且是混合客群
            Map<String, String> map = new HashMap<>();
            map.put("groupId", bean.getCustomerId());
            if ("dynamic".equals(param) && !mapper.dynamicOnly(map)) {
                /**
                 * 1、查询出动态标签客群的文件名 2、SFTP将文件从服务云服务器上传至统一标签平台 3、调用统一标签平台接口上报动态标签客群信息
                 */
                Map<String, String> dynamicMap = new HashMap<>();
                dynamicMap.put("groupId", bean.getCustomerId());
                // 文件上传失败标识
                dynamicMap.put("isTrans", "0");
                Map<String, Object> dynamicCustomerInfo = mapper.dynamicCustomerInfo(dynamicMap);
                MusicRuleRequestBean musicRuleRequestBean = new MusicRuleRequestBean();
                musicRuleRequestBean.setCustomerId(bean.getCustomerId());
                boolean isDown = false;
                if (null != dynamicCustomerInfo.get("uidFileName")) {
                    String fileName = String.valueOf(dynamicCustomerInfo.get("uidFileName"));
                    musicRuleRequestBean.setUidPath(fileName);
                    isDown = sftpUtils.fileSyncToLabel(fileName);
                    if (!isDown) {
                        userGroupInfo.put("createStatus", "6");
                        userGroupInfo.put("remark", "UID临时客群未能成功同步至统一标签服务平台");
                        mapper.updateUserGroupInfo(userGroupInfo);
                        mapper.updateDynamicCustomerInfo(dynamicMap);
                        // 更新使用该人群的待进行策略
                        updateStrategyInfo(bean.getCustomerId());
                        responseBean.setCode(LabelCustomerResponseCodeEnum.FILE_TRANS_FAIL.getCode());
                        responseBean.setMsg("UID临时客群未能成功同步至统一标签服务平台");
                        return responseBean;
                    }
                }
                if (null != dynamicCustomerInfo.get("deviceFileName")) {
                    String fileName = String.valueOf(dynamicCustomerInfo.get("deviceFileName"));
                    musicRuleRequestBean.setImeiIdfaPath(fileName);
                    isDown = sftpUtils.fileSyncToLabel(fileName);
                    if (!isDown) {
                        userGroupInfo.put("createStatus", "6");
                        userGroupInfo.put("remark", "设备号临时客群未能成功同步至统一标签服务平台");
                        mapper.updateUserGroupInfo(userGroupInfo);
                        mapper.updateDynamicCustomerInfo(dynamicMap);
                        // 更新使用该人群的待进行策略
                        updateStrategyInfo(bean.getCustomerId());
                        responseBean.setCode(LabelCustomerResponseCodeEnum.FILE_TRANS_FAIL.getCode());
                        responseBean.setMsg("设备号临时客群未能成功同步至统一标签服务平台");
                        return responseBean;
                    }
                }
                if (null != dynamicCustomerInfo.get("msisdnFileName")) {
                    String fileName = String.valueOf(dynamicCustomerInfo.get("msisdnFileName"));
                    musicRuleRequestBean.setPhonePath(fileName);
                    isDown = sftpUtils.fileSyncToLabel(fileName);
                    if (!isDown) {
                        userGroupInfo.put("createStatus", "6");
                        userGroupInfo.put("remark", "手机号临时客群未能成功同步至统一标签服务平台");
                        mapper.updateUserGroupInfo(userGroupInfo);
                        mapper.updateDynamicCustomerInfo(dynamicMap);
                        // 更新使用该人群的待进行策略
                        updateStrategyInfo(bean.getCustomerId());
                        responseBean.setCode(LabelCustomerResponseCodeEnum.FILE_TRANS_FAIL.getCode());
                        responseBean.setMsg("手机号临时客群未能成功同步至统一标签服务平台");
                        return responseBean;
                    }
                }
                log.info("向标签服务平台上报文件规则：{}", musicRuleRequestBean.toString());
                // 将人群状态修改至创建中
                userGroupInfo.put("createStatus", "4");
                mapper.updateUserGroupInfo(userGroupInfo);
                report(musicRuleRequestBean);
                // 更新客群时查询该人群变色龙动态人群是否正在使用，使用中时更新redis中客群信息
                syncUserGroupInfo(bean.getCustomerId());
            } else {
                if ("1".equals(bean.getCustomerStatus())) {
                    // 拉取文件更新客群uid到redis
                    userGroupInfo.put("createStatus", "4");
                    userGroupInfo.put("dataWrittenToRedis", "1");
                } else {
                    userGroupInfo.put("createStatus", "6");
                    userGroupInfo.put("remark", bean.getRemark());
                    // 更新使用该人群的待进行策略
                    updateStrategyInfo(bean.getCustomerId());
                }
                userGroupInfo.put("clientUser", bean.getUidNum());
                userGroupInfo.put("mobileUser", bean.getMsisdnNum());
                userGroupInfo.put("deviceUser", bean.getDeviceNum());
                userGroupInfo.put("userGroupSize", maxValue(Integer.parseInt(bean.getUidNum()),
                    Integer.parseInt(bean.getMsisdnNum()), Integer.parseInt(bean.getDeviceNum())));
                // 更新数据库
                log.info("更新客群状态数据入库：{}", userGroupInfo.toString());
                mapper.updateUserGroupInfo(userGroupInfo);
                // 更新客群时查询该人群变色龙动态人群是否正在使用，使用中时更新redis中客群信息
                syncUserGroupInfo(bean.getCustomerId());
            }
        } catch (Exception e) {
            responseBean.setCode(LabelCustomerResponseCodeEnum.SYSTEM_ERR.getCode());
            responseBean.setMsg(LabelCustomerResponseCodeEnum.SYSTEM_ERR.getMsg());
            return responseBean;
        }
        responseBean.setCode(LabelCustomerResponseCodeEnum.SUCCESS.getCode());
        responseBean.setMsg(LabelCustomerResponseCodeEnum.SUCCESS.getMsg());
        return responseBean;
    }

    /**
     * 人群创建失败时，更新待使用的策略信息
     *
     * @param groupId 人群id
     */
    private void updateStrategyInfo(String groupId) {
        // 人群创建失败，查询待使用的策略是否引用该人群，修改策略状态
        List<Map<String, Object>> strategyList = strategyMapper.queryStrategyByGroupId(groupId);
        if (strategyList != null && strategyList.size() > 0) {
            int count = 0;
            for (Map<String, Object> strategy : strategyList) {
                strategy.put("executeStatus", StrategyConstants.EXECUTE_REJECTED);
                strategy.put("approverId", "000");
                strategy.put("approverName", "admin");
                strategy.put("approveStatus", ApproveConstans.APPROVE_REFUSE);
                strategy.put("approveDesc", "人群提取失败");
                // 修改策略信息
                strategyMapper.updateApproveInfo(strategy);
                // 增加审批记录
                approveMapper.createApproveByMap(strategy);
                count++;
            }
            log.info("已将{}条策略驳回", count);
        } else {
            log.info("当前无待进行的策略使用该人群：{}", groupId);
        }
    }

    /**
     * 同步客群信息至redis
     *
     * @param groupId 客群id
     */
    private int syncUserGroupUid(String groupId) {
        // 设置3个月过期时间
        Long expire = 1000L * 60 * 60 * 24 * 90;
        log.info("开始更新人群：{}", groupId);
        Map<String, Object> strategy = new HashMap<>();
        strategy.put("strategyId", System.currentTimeMillis());
        strategy.put("strategyName", System.currentTimeMillis());
        strategy.put("groupId", groupId);
        strategy.put("approverName", System.currentTimeMillis());
        strategy.put("creatorName", System.currentTimeMillis());
        File phoneFile = DownloadByFtp.getLabelUserGroup(strategy, labelPrefix + postUrl, 1);
        getGroupInfoToRedis(phoneFile, groupId + "-phone", expire);
        File uidFile = DownloadByFtp.getLabelUserGroup(strategy, labelPrefix + postUrl, 3);
        return getGroupInfoToRedis(uidFile, groupId + "-uid", expire);
    }

    /**
     * 同步客群信息至redis
     *
     * @param groupId 客群id
     */
    private void syncUserGroupInfo(String groupId) {
        List<ConditionRelation> conditionRelations = mapper.queryByGroupId(groupId);
        if (conditionRelations.size() > 0) {
            // 获取客群当前过期时间
            Long expire = redisService.getExpire(groupId + "-phone");
            // 删除当前redis中key
            redisService.remove(groupId + "phone", groupId + "imei", groupId + "uid");
            // 读取人群信息，更新redis中客群信息
            String approveName = mapper.queryApproveName(conditionRelations.get(0).getActivityId());
            File msisdnFile = DownloadByFtp.getLabelUserGroupForGPush(groupId,
                conditionRelations.get(0).getActivityId(), labelPrefix + postUrl, 1, approveName);
            getGroupInfoToRedis(msisdnFile, groupId + "-phone", expire);
            File uidFile = DownloadByFtp.getLabelUserGroupForGPush(groupId, conditionRelations.get(0).getActivityId(),
                labelPrefix + postUrl, 3, approveName);
            getGroupInfoToRedis(uidFile, groupId + "-uid", expire);
        }
    }

    /**
     * 客群静态标签规则上报
     *
     * @param bean
     * @return
     */
    @Override
    public LabelCustomerResponseBean detail(LabelCustomerDetailRequestBean bean) {
        LabelCustomerResponseBean response = new LabelCustomerResponseBean();
        if (null == bean.getCustomerId() || "".equals(bean.getCustomerId()) || null == bean.getIsLabelCustomer()
            || "".equals(bean.getIsLabelCustomer())) {
            log.info("客群静态标签规则上报缺少必须参数");
            response.setCode(LabelCustomerResponseCodeEnum.PARAM_ERR.getCode());
            response.setMsg(LabelCustomerResponseCodeEnum.PARAM_ERR.getMsg());
            return response;
        }
        log.info("客群静态标签规则上报：{}", bean.toString());
        // 更新客群时查询该人群变色龙动态人群是否正在使用，使用中时更新redis中客群信息
        syncUserGroupInfo(bean.getCustomerId());
        if ("1".equals(bean.getIsLabelCustomer())) {
            HashMap<String, String> map = new HashMap<>();
            map.put("groupId", bean.getCustomerId());
            map.put("isLabelCustomer", "1");
            map.put("data", bean.getData());
            mapper.updateUserGroupInfo(map);
            if (mapper.isCustomerExist(map)) {
                mapper.updateStaticCustomerInfo(map);
            } else {
                mapper.createStaticCustomerInfo(map);
            }
        } else {
            HashMap<String, String> map = new HashMap<>();
            map.put("groupId", bean.getCustomerId());
            map.put("isLabelCustomer", "0");
            map.put("data", "");
            mapper.updateUserGroupInfo(map);
            if (mapper.isCustomerExist(map)) {
                mapper.updateStaticCustomerInfo(map);
            }
        }
        response.setCode(LabelCustomerResponseCodeEnum.SUCCESS.getCode());
        response.setMsg(LabelCustomerResponseCodeEnum.SUCCESS.getMsg());
        return response;
    }

    /**
     * 读取人群信息存入redis中
     *
     * @param file 文件信息
     * @param key redis的key
     * @param expireTime 过期时间
     */
    private int getGroupInfoToRedis(File file, String key, Long expireTime) {
        if (file != null && file.length() != 0) {
            String str;
            Set<String> set = new HashSet<>();
            try {
                BufferedReader br = new BufferedReader(new FileReader(file));
                while ((str = br.readLine()) != null) {
                    if (!"".equals(str) && !str.startsWith("GEN_")) {
                        set.add(str);
                    }
                }
                redisService.setCollectToRedis(key, set, expireTime);
                br.close();
            } catch (IOException e) {
                log.info("读取标签平台文件异常：{}", e.getMessage());
                throw new MyException(StatusEnum.FILE_NOT_EXISTS, "读取标签平台文件异常");
            }
            return set.size();
        }
        return 0;
    }

    /**
     * 查询指定客群的静态标签信息
     *
     * @param groupId
     * @return
     */
    @Override
    public ResultObject staticLabelInfo(String groupId) {
        ResultObject res = new ResultObject();
        try {
            res.setCode(StatusEnum.SUCCESS.getCode());
            res.setMsg(StatusEnum.SUCCESS.getMsg());
            Map<String, String> map = new HashMap<>();
            map.put("groupId", groupId);
            res.setData(mapper.staticLabelInfo(map));
            return res;
        } catch (Exception e) {
            res.setCode(StatusEnum.ERROR.getCode());
            res.setMsg(StatusEnum.ERROR.getMsg());
            return res;
        }
    }

    /**
     * 文件上传至统一标签服务平台
     *
     * @param bean
     * @return
     */
    @Override
    public LabelCustomerResponseBean fileTransByManual(MusicRuleRequestBean bean) {
        log.info("文件上传至统一标签服务平台:{}", bean.toString());
        LabelCustomerResponseBean response = new LabelCustomerResponseBean();
        try {
            RestHttpPost post = new RestHttpPost();
            post.doRest(bean, LABEL_PREFIX + CUSTOMER_RULE);
            HashMap<String, String> userGroupInfo = new HashMap<>();
            userGroupInfo.put("groupId", bean.getCustomerId());
            userGroupInfo.put("createStatus", "4");
            userGroupInfo.put("remark", "重试文件同步");
            mapper.updateUserGroupInfo(userGroupInfo);
            Map<String, String> dynamicMap = new HashMap<>();
            dynamicMap.put("groupId", bean.getCustomerId());
            // 文件上传失败标识
            dynamicMap.put("isTrans", "1");
            mapper.updateDynamicCustomerInfo(dynamicMap);
            response.setCode(LabelCustomerResponseCodeEnum.SUCCESS.getCode());
            response.setMsg(LabelCustomerResponseCodeEnum.SUCCESS.getMsg());
            return response;
        } catch (Exception e) {
            log.error("上报临时客群信息异常:{}", e.getMessage());
            response.setCode(LabelCustomerResponseCodeEnum.CUSTOMER_RULE_REQUEST_ERROR.getCode());
            response.setMsg(LabelCustomerResponseCodeEnum.CUSTOMER_RULE_REQUEST_ERROR.getMsg());
            return response;
        }

    }

    /**
     * 客群重组上报
     *
     * @param groupId
     * @return
     */
    @Override
    public LabelCustomerResponseBean customerMerge(String groupId) {
        LabelCustomerResponseBean bean = new LabelCustomerResponseBean();
        try {
            Map<String, Object> master = new HashMap<>();
            master.put("groupId", groupId);
            master = mapper.recombineCustomerMasterInfo(master);

            Map<String, Object> masterInfo = new HashMap<>();
            masterInfo.put("groupId", master.get("masterCustomerId"));
            masterInfo.put("masterCustomerId", groupId);
            masterInfo = mapper.recombineCustomerSlaveInfo(masterInfo);

            Map<String, Object> slaveInfo = new HashMap<>();
            slaveInfo.put("groupId", master.get("slaveCustomerId"));
            slaveInfo.put("masterCustomerId", groupId);
            slaveInfo = mapper.recombineCustomerSlaveInfo(slaveInfo);

            CustomerMergeRequestBean mergeBean = new CustomerMergeRequestBean();
            mergeBean.setMergeCustomerId(String.valueOf(master.get("customerId")));
            mergeBean.setUserId(String.valueOf(master.get("userId")));
            mergeBean.setGroupId(String.valueOf(master.get("groupId")));
            mergeBean.setCalType(Integer.valueOf(String.valueOf(master.get("calType"))));
            CustomerFileBean masterBean = new CustomerFileBean();
            masterBean.setCustomerId(String.valueOf(masterInfo.get("customerId")));
            masterBean.setType(Integer.valueOf(String.valueOf(masterInfo.get("customerType"))));
            if (null != masterInfo.get("uidFileName")) {
                masterBean.setUidPath(String.valueOf(masterInfo.get("uidFileName")));
            }
            if (null != masterInfo.get("deviceFileName")) {
                masterBean.setImeiIdfaPath(String.valueOf(masterInfo.get("deviceFileName")));
            }
            if (null != masterInfo.get("msisdnFileName")) {
                masterBean.setPhonePath(String.valueOf(masterInfo.get("msisdnFileName")));
            }
            CustomerFileBean slaveBean = new CustomerFileBean();
            slaveBean.setCustomerId(String.valueOf(slaveInfo.get("customerId")));
            slaveBean.setType(Integer.valueOf(String.valueOf(slaveInfo.get("customerType"))));
            if (null != slaveInfo.get("uidFileName")) {
                slaveBean.setUidPath(String.valueOf(slaveInfo.get("uidFileName")));
            }
            if (null != slaveInfo.get("deviceFileName")) {
                slaveBean.setImeiIdfaPath(String.valueOf(slaveInfo.get("deviceFileName")));
            }
            if (null != slaveInfo.get("msisdnFileName")) {
                slaveBean.setPhonePath(String.valueOf(slaveInfo.get("msisdnFileName")));
            }
            mergeBean.setCustomerFile1(masterBean);
            mergeBean.setCustomerFile2(slaveBean);
            log.info("上报客群重组信息：{}", mergeBean.toString());
            doPost(mergeBean);
            log.info("更新上传状态：{}", master.get("customerId"));
            Map<String, Object> updateRecombineMaster = new HashMap<>();
            updateRecombineMaster.put("groupId", master.get("customerId"));
            mapper.updateRecombineCustomerMasterInfo(updateRecombineMaster);
            bean.setCode(LabelCustomerResponseCodeEnum.SUCCESS.getCode());
            bean.setMsg(LabelCustomerResponseCodeEnum.SUCCESS.getMsg());
            return bean;
        } catch (Exception e) {
            log.error("上报重组客群失败：{}", e.getMessage());
            bean.setCode(LabelCustomerResponseCodeEnum.SYSTEM_ERR.getCode());
            bean.setMsg(LabelCustomerResponseCodeEnum.SYSTEM_ERR.getMsg());
            return bean;
        }
    }

    /**
     * 返回abc三者最大值
     *
     * @param a
     * @param b
     * @param c
     * @return
     */
    public static String maxValue(int a, int b, int c) {
        int temp = a > b ? a : b;
        return String.valueOf(temp > c ? temp : c);
    }

    /**
     * 状态上报
     *
     * @param bean
     */
    private void report(MusicRuleRequestBean bean) {
        RestHttpPost post = new RestHttpPost();
        post.doRest(bean, LABEL_PREFIX + CUSTOMER_RULE);
    }

    /**
     * 重组状态上报
     *
     * @param bean
     */
    private void doPost(CustomerMergeRequestBean bean) {
        RestHttpPost post = new RestHttpPost();
        post.doRest(bean, LABEL_PREFIX + CUSTOMER_MERGE);
    }
}
